#ifndef HEADERS_CONVERSION_H
#define HEADERS_CONVERSION_H

namespace iloki {

/*! \brief A generic class determine whether type 
 * T could be converted to U.
 *
 * A helper class used by SUPERSUBCLASS macro to determine 
 * derivation relationship between types. 
 * Use conversion<T, U>::exists to check whether type T 
 * could beconverted to U. 
 */
template <class T, class U> class conversion{
	/*! \brief An arbitrary type we use to distinguish the 
	 * return value of test().
	 *
	 * @see big
	 */
	typedef char small;
	/*! \brief An arbitrary type we use to distinguish the 
	 * return value of test().
	 *
	 *
	 */
	class big { char dummy[2]; };

	/*! \brief The exact match call when the input para 
	 * type is U or could be converted to U.*/
	static small test(U);

	/*! \brief  
	 * 
	 * Although pass a C++ object into. It doesn't matter. 
	 * We never call it. Even though, test(...) doesn't 
	 * need to implement.
	 */
	static big test(...);
	/*! \brief A strawman function. Just in case that type 
	 * T has a private default constructor.
	 *
	 * Here we just need the return type. Actually, we 
	 * never call the constructor of T.
	 */
	static T makeT();

public:
	/*! \brief A compile-time constant indicating whether 
	 * type T could be 
	 * converted to U.
	 *
	 * If exists == true, T could be converted to U.
	 * If exists == false, T cannot be converted to U.
	 */
	enum { exists = sizeof(test(makeT())) == sizeof(small) };
	/*! \brief A compile-time constant indicating whether
	 * type T and U could be converted to each other.
	 */
	enum { exists2way = (exists && conversion<U, T>::exists) };
	/*! \brief Whether T and U are the same type. */
	enum { same_type = false };
}; 

/*! \brief A partial specialized version of conversion 
 * for situation that U and T are the same type.
 */
template <class T> class conversion<T, T> {
public:
	enum { exists = 1, exists2way = 1, same_type = 1 };
};

/*! \brief A macro determine whether type U derived from type T.
 *
 * @param T The base class.
 * @param U The evaluated type.
 * @return true if U derived from T, else false.
 * */
#define SUPERSUBCLASS(T, U) \
	(conversion<const U*, const T*>::exists && \
	 !conversion<const T*, void *>::same_type)

/*! \brief A more strict macro determine whether 
 * type U derived from type T (U and T cannot be the same type.)
 *
 * @param T The base class.
 * @param U The evaluated type.
 * @return true if U derived from T, else false.
 * */
#define SUPERSUBCLASS_STRICT(T, U) \
	(SUPERSUBCLASS(T, U) && \
	 !conversion<const T, const U>::same_type)

};
#endif
